package com.panopset.security;

import static com.panopset.Util.*;

import java.io.StringWriter;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import com.panopset.Alert;
import com.panopset.Base64Coder;

/**
 *
 * Sites used to create this:
 *
 * http://www.exampledepot.com/egs/javax.crypto/PassKey.html
 * http://java.sun.com/developer/technicalArticles/Security/AES/AES_v1.html
 *
 */
public class Encrypter {
    final int cols;
    Cipher ecipher;
    Cipher dcipher;

    byte[] salt = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32,
            (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03 };

    int iterationCount = 19;

    public Encrypter(String passPhrase, int cols) {
        this.cols = cols;
        try {
            KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt,
                    iterationCount);
            SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES")
                    .generateSecret(keySpec);
            ecipher = Cipher.getInstance(key.getAlgorithm());
            dcipher = Cipher.getInstance(key.getAlgorithm());

            AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt,
                    iterationCount);

            ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
            dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
        } catch (Exception e) {
            log(e);
        }
    }

    public String encrypt(String str) {
        try {
            byte[] utf8 = str.getBytes("UTF8");

            byte[] enc = ecipher.doFinal(utf8);

            String rtn = new String(Base64Coder.encode(enc));

            StringWriter sw = new StringWriter();

            if (cols > 0) {
                int count = 0;
                for (int i=0; i<rtn.length(); i++) {
                    if (++count == cols) {
                        count = 0;
                        sw.append(DOS_RTN);
                    }
                    sw.append(rtn.charAt(i));
                }
                return sw.toString();
            } else {
                return rtn;
            }
        } catch (Exception e) {
            log(e);
            Alert.red(x("Check password, see log for details" + PERIOD));
        }
        return null;
    }

    public String decrypt(String str) {
        try {
            byte[] dec = Base64Coder.decode(str.replace(""+(char)13, "").replace(""+(char)10, "").trim());
            byte[] utf8 = dcipher.doFinal(dec);
            return new String(utf8, "UTF8");
        } catch (Exception e) {
            log(e);
            Alert.red(x("Check password, see log for details" + PERIOD));
        }
        return null;
    }
}
